home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 58678 / 58678.xpi / share / share.js
Text File  |  2010-01-10  |  16KB  |  534 lines

  1. let EXPORTED_SYMBOLS = ["clip", "util", "persist"];
  2.  
  3. const Cc = Components.classes;
  4. const Ci = Components.interfaces;
  5.  
  6. const prefRoot = "extensions.clipple";
  7. const extensionName = "clipple";
  8.  
  9. // Clipboard Holder {{ ====================================================== //
  10.  
  11. let clip = {
  12.     ring : [],
  13.  
  14.     get textLengthMax() {
  15.         return util.getIntPref(util.getPrefKey("text_length_max"), -1);
  16.     },
  17.  
  18.     get ringSizeMax() {
  19.         return util.getIntPref(util.getPrefKey("number_of_clipboards"), 15);
  20.     },
  21.  
  22.     get limitByTextLength() {
  23.         return util.getBoolPref(util.getPrefKey("limit_by_text_length"), false);
  24.     },
  25.  
  26.     pushText: function clip_pushText(aText) {
  27.         let textLen = aText.length;
  28.  
  29.         let textLengthMax = clip.textLengthMax;
  30.         let ringSizeMax   = clip.ringSizeMax;
  31.  
  32.         if (textLen && (!clip.limitByTextLength || textLen <= textLengthMax))
  33.         {
  34.             if (!clip.ring.length || clip.ring[0] !== aText)
  35.             {
  36.                 if (clip.ring.length >= ringSizeMax)
  37.                     clip.ring.pop();
  38.  
  39.                 clip.ring.unshift(aText);
  40.             }
  41.         }
  42.     },
  43.  
  44.     sync: function clip_sync() {
  45.         let text = util.clipboardGet();
  46.  
  47.         if (text)
  48.         {
  49.             if (!clip.ring.length || clip.ring[0] !== text)
  50.                 clip.pushText(text);
  51.         }
  52.     }
  53. };
  54.  
  55. // }} ======================================================================= //
  56.  
  57. // Utilities {{ ============================================================= //
  58.  
  59. let mPrefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
  60.  
  61. let util = {
  62.     getPrefKey: function (aName) {
  63.         return prefRoot + "." + aName;
  64.     },
  65.  
  66.     setBoolPref: function (aPrefName, aPrefValue) {
  67.         try
  68.         {
  69.             mPrefService.setBoolPref(aPrefName, aPrefValue);
  70.         }
  71.         catch (e) {}
  72.     },
  73.  
  74.     getBoolPref: function (aPrefName, aDefVal) {
  75.         try
  76.         {
  77.             return mPrefService.getBoolPref(aPrefName);
  78.         }
  79.         catch (e)
  80.         {
  81.             return typeof aDefVal === "undefined" ? null : aDefVal;
  82.         }
  83.  
  84.         return null;
  85.     },
  86.  
  87.     /**
  88.      * set unicode string preference value
  89.      * @param {string} aStringKey key of the preference
  90.      * @param {string} aValue value of the preference specified by <b>aStringKey</b>
  91.      */
  92.     setUnicharPref: function (aPrefName, aPrefValue) {
  93.         try
  94.         {
  95.             let str = Cc["@mozilla.org/supports-string;1"].createInstance(Ci.nsISupportsString);
  96.             str.data = aPrefValue;
  97.             mPrefService.setComplexValue(aPrefName, Ci.nsISupportsString, str);
  98.         }
  99.         catch (e) {}
  100.     },
  101.  
  102.     /**
  103.      * get unicode string preference value. when localized version is available,
  104.      * that one is used.
  105.      * @param {string} aStringKey key of the preference
  106.      * @returns {string} fetched preference value specified by <b>aStringKey</b>
  107.      */
  108.     getUnicharPref: function (aStringKey) {
  109.         return self.getLocalizedUnicharPref(aStringKey)
  110.             || self.copyUnicharPref(aStringKey);
  111.     },
  112.  
  113.     getLocalizedUnicharPref: function (aPrefName, aDefVal) {
  114.         try
  115.         {
  116.             return mPrefService.getComplexValue(aPrefName, Ci.nsIPrefLocalizedString).data;
  117.         }
  118.         catch (e)
  119.         {
  120.             return typeof aDefVal === "undefined" ? null : aDefVal;
  121.         }
  122.  
  123.         return null;        // quiet warnings
  124.     },
  125.  
  126.     setIntPref: function (aPrefName, aPrefValue) {
  127.         try
  128.         {
  129.             mPrefService.setIntPref(aPrefName, aPrefValue);
  130.         }
  131.         catch (e) {}
  132.     },
  133.  
  134.     getIntPref: function (aPrefName, aDefVal) {
  135.         try
  136.         {
  137.             return mPrefService.getIntPref(aPrefName);
  138.         }
  139.         catch (e)
  140.         {
  141.             return typeof aDefVal === "undefined" ? null : aDefVal;
  142.         }
  143.  
  144.         return null;        // quiet warnings
  145.     },
  146.  
  147.     /**
  148.      * get localized string
  149.      * @param {string} aStringKey string bundle key
  150.      * @param {[string]} aReplacements arguments be to replace the %S in format
  151.      * @returns {string} localized key on success or string key on failure
  152.      */
  153.     getLocaleString: function util_getLocaleString(aStringKey, aReplacements) {
  154.         if (!util._stringBundle)
  155.         {
  156.             const bundleURI = "chrome://clipple/locale/clipple.properties";
  157.             let   bundleSvc = Cc["@mozilla.org/intl/stringbundle;1"].getService(Ci.nsIStringBundleService);
  158.  
  159.             util._stringBundle = bundleSvc.createBundle(bundleURI);
  160.         }
  161.  
  162.         try
  163.         {
  164.             if (!aReplacements)
  165.                 return util._stringBundle.GetStringFromName(aStringKey);
  166.             else
  167.                 return util._stringBundle
  168.                 .formatStringFromName(aStringKey, aReplacements, aReplacements.length);
  169.         }
  170.         catch (e)
  171.         {
  172.             return aStringKey;
  173.         }
  174.     },
  175.  
  176.     /**
  177.      * store <b>aText</b> to the system clipboard
  178.      * @param {string} aText
  179.      */
  180.     clipboardSet: function util_clipboardSet(aText) {
  181.         let ss = Cc['@mozilla.org/supports-string;1'].createInstance(Ci.nsISupportsString);
  182.         if (!ss)
  183.             return;
  184.  
  185.         let trans = Cc['@mozilla.org/widget/transferable;1'].createInstance(Ci.nsITransferable);
  186.         if (!trans)
  187.             return;
  188.  
  189.         let clipid = Ci.nsIClipboard;
  190.         let clipboard   = Cc['@mozilla.org/widget/clipboard;1'].getService(clipid);
  191.         if (!clipboard)
  192.             return;
  193.  
  194.         ss.data = aText;
  195.         trans.addDataFlavor('text/unicode');
  196.         trans.setTransferData('text/unicode', ss, aText.length * 2);
  197.         clipboard.setData(trans, null, clipid.kGlobalClipboard);
  198.     },
  199.  
  200.     /**
  201.      * Get content in the system clipboard
  202.      * @throws Exception
  203.      * @returns {string} content in the clipboard
  204.      */
  205.     clipboardGet: function util_clipboardGet() {
  206.         try
  207.         {
  208.             let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
  209.  
  210.             let trans = Cc["@mozilla.org/widget/transferable;1"].createInstance(Ci.nsITransferable);
  211.             trans.addDataFlavor("text/unicode");
  212.  
  213.             clipboard.getData(trans, clipboard.kGlobalClipboard);
  214.  
  215.             let str       = {};
  216.             let strLength = {};
  217.  
  218.             trans.getTransferData("text/unicode", str, strLength);
  219.             if (str)
  220.                 str = str.value.QueryInterface(Ci.nsISupportsString);
  221.  
  222.             return str ? str.data.substring(0, strLength.value / 2) : null;
  223.         }
  224.         catch (e)
  225.         {
  226.             return null;
  227.         }
  228.     },
  229.  
  230.     clipboardClear: function util_clipboardClear() {
  231.         try
  232.         {
  233.             util.clipboardSet("");
  234.             // let clipboard = Cc["@mozilla.org/widget/clipboard;1"].getService(Ci.nsIClipboard);
  235.             // clipboard.emptyClipboard(clipboard.kGlobalClipboard);
  236.         }
  237.         catch (x) {}
  238.     },
  239.  
  240.     // Char code {{ ============================================================= //
  241.  
  242.     /**
  243.      * convert given string's char code
  244.      * original function from sage
  245.      * @param {string} aString target string
  246.      * @param {string} aCharCode aimed charcode
  247.      * @returns {string} charcode converted string
  248.      */
  249.     convertCharCodeFrom: function (aString, aCharCode) {
  250.         let UConvID = "@mozilla.org/intl/scriptableunicodeconverter";
  251.         let UConvIF = Ci.nsIScriptableUnicodeConverter;
  252.         let UConv   = Cc[UConvID].getService(UConvIF);
  253.  
  254.         let tmpString = "";
  255.         try
  256.         {
  257.             UConv.charset = aCharCode;
  258.             tmpString = UConv.ConvertFromUnicode(aString);
  259.         }
  260.         catch (e)
  261.         {
  262.             tmpString = null;
  263.         }
  264.  
  265.         return tmpString;
  266.     },
  267.  
  268.     // }} ======================================================================= //
  269.  
  270.     /**
  271.      * get extension's special directory
  272.      * original function from sage
  273.      * @param {string} aProp special directory type
  274.      * @returns {file} special directory
  275.      */
  276.     getSpecialDir: function (aProp) {
  277.         return Cc['@mozilla.org/file/directory_service;1'].getService(Ci.nsIProperties)
  278.             .get(aProp, Ci.nsILocalFile);
  279.     },
  280.  
  281.     // IO {{ ==================================================================== //
  282.  
  283.     /**
  284.      * Open file specified by <b>aPath</b> and returns it.
  285.      * @param {string} aPath file path to be opened
  286.      * @returns {nsILocalFile} opened file
  287.      */
  288.     openFile: function (aPath) {
  289.         let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
  290.         file.initWithPath(aPath);
  291.  
  292.         return file;
  293.     },
  294.  
  295.     /**
  296.      * Open text file, read its content, and returns it.
  297.      * @param {string} aPath file path to be read
  298.      * @param {string} aCharset specify text charset
  299.      * @returns {string} text content of the file
  300.      * @throws {}
  301.      */
  302.     readTextFile: function (aPath, aCharset) {
  303.         let file = util.openFile(aPath);
  304.  
  305.         if (!file.exists())
  306.             throw new Exception(aPath + " not found");
  307.  
  308.         let fileStream = Cc["@mozilla.org/network/file-input-stream;1"]
  309.             .createInstance(Ci.nsIFileInputStream);
  310.         fileStream.init(file, 1, 0, false);
  311.  
  312.         let converterStream = Cc["@mozilla.org/intl/converter-input-stream;1"]
  313.             .createInstance(Ci.nsIConverterInputStream);
  314.  
  315.         if (!aCharset)
  316.             aCharset = 'UTF-8';
  317.         converterStream.init(fileStream, aCharset, fileStream.available(),
  318.                              converterStream.DEFAULT_REPLACEMENT_CHARACTER);
  319.  
  320.         let out = {};
  321.         converterStream.readString(fileStream.available(), out);
  322.  
  323.         converterStream.close();
  324.         fileStream.close();
  325.  
  326.         return out.value;
  327.     },
  328.  
  329.     /**
  330.      * Write <b>aString</b> to the local file specified by <b>aPath</b>.
  331.      * Overwrite confirmation will be ommitted if <b>aForce</b> is true.
  332.      * "Don't show me again" checkbox value managed by <b>aCheckID</b>.
  333.      * @param {string} aString
  334.      * @param {string} aPath
  335.      * @param {boolean} aForce
  336.      * @param {string} aCheckID
  337.      * @throws {}
  338.      */
  339.     writeTextFile: function (aString, aPath, aForce) {
  340.         let file = util.openFile(aPath);
  341.  
  342.         if (file.exists() && !aForce &&
  343.             util.confirm(util.getLocaleString("overWriteConfirmationTitle"),
  344.                          util.getLocaleString("overWriteConfirmation", [aPath])))
  345.         {
  346.             throw new Exception("Canceled by user");
  347.         }
  348.  
  349.         let fileStream = Cc["@mozilla.org/network/file-output-stream;1"]
  350.             .createInstance(Ci.nsIFileOutputStream);
  351.         fileStream.init(file, 0x02 | 0x08 | 0x20, 0644, false);
  352.  
  353.         let wrote = fileStream.write(aString, aString.length);
  354.         if (wrote != aString.length)
  355.         {
  356.             throw new Exception("Failed to write whole string");
  357.         }
  358.  
  359.         fileStream.close();
  360.     },
  361.  
  362.     createDirectory: function (aLocalFile) {
  363.         if (aLocalFile.exists() && !aLocalFile.isDirectory())
  364.                 aLocalFile.remove(false);
  365.  
  366.         if (!aLocalFile.exists())
  367.             aLocalFile.create(Ci.nsIFile.DIRECTORY_TYPE, 0755);
  368.  
  369.         return aLocalFile;
  370.     },
  371.  
  372.     getExtensionLocalDirectoryRoot: function () {
  373.         const extName = extensionName;
  374.  
  375.         let extDir = util.getSpecialDir("ProfD");
  376.         extDir.append(extName);
  377.  
  378.         return util.createDirectory(extDir);
  379.     },
  380.  
  381.     getExtensionLocalDirectory: function (aDirName) {
  382.         let localDir = util.getExtensionLocalDirectoryRoot();
  383.         localDir.append(aDirName);
  384.  
  385.         return util.createDirectory(localDir);
  386.     },
  387.  
  388.     // }} ======================================================================= //
  389.  
  390.     /**
  391.      * window.confirm alternative.
  392.      * This method can specify the window title while window.confirm can't.
  393.      * @param {} aTitle
  394.      * @param {} aMessage
  395.      * @returns {}
  396.      */
  397.     confirm: function (aTitle, aMessage, aWindow) {
  398.         let prompts = Cc["@mozilla.org/embedcomp/prompt-service;1"]
  399.             .getService(Ci.nsIPromptService);
  400.  
  401.         return prompts.confirm(aWindow || util.getWindow("navigator:browser"), aTitle, aMessage);
  402.     },
  403.  
  404.     insertText: function util_insertText(text, doc) {
  405.         let command    = 'cmd_insertText';
  406.         let controller = doc.commandDispatcher.getControllerForCommand(command);
  407.  
  408.         if (controller && controller.isCommandEnabled(command))
  409.         {
  410.             controller = controller.QueryInterface(Ci.nsICommandController);
  411.             let params = Cc['@mozilla.org/embedcomp/command-params;1'];
  412.             params = params.createInstance(Ci.nsICommandParams);
  413.             params.setStringValue('state_data', text);
  414.             controller.doCommandWithParams(command, params);
  415.         }
  416.     },
  417.  
  418.     format: function util_format(aFormat) {
  419.         for (let i = 1; i < arguments.length; ++i)
  420.             aFormat = aFormat.replace("%s", arguments[i]);
  421.         return aFormat;
  422.     },
  423.  
  424.     log: function util_log(aMsg) {
  425.         let logs = Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService);
  426.  
  427.         try
  428.         {
  429.             logs.logStringMessage(aMsg);
  430.         }
  431.         catch (x)
  432.         {
  433.             logs.logStringMessage(x);
  434.         }
  435.     },
  436.  
  437.     message: function util_message() {
  438.         util.log(util.format.apply(this, arguments));
  439.     },
  440.  
  441.     getWindow: function (aType) {
  442.         let wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
  443.         return wm.getMostRecentWindow(aType);
  444.     },
  445.  
  446.     visitLink: function (aURI, aBackGround) {
  447.         let mainWindow = util.getWindow("navigator:browser");
  448.  
  449.         mainWindow.getBrowser().loadOneTab(aURI, null, null, null, aBackGround || false, false);
  450.     }
  451. };
  452.  
  453. // Persistent object {{ ===================================================== //
  454.  
  455. let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
  456.  
  457. let persist = {
  458.     getFile: function (aName) {
  459.         let dir = util.getExtensionLocalDirectory('persistent');
  460.         dir.append(aName.replace(/-/g, "_") + ".json");
  461.  
  462.         return dir;
  463.     },
  464.  
  465.     preserve: function (aName, aObj) {
  466.         let file    = persist.getFile(aName);
  467.         let encoded = json.encode(aObj);
  468.  
  469.         util.writeTextFile(util.convertCharCodeFrom(encoded, "UTF-8"), file.path, true);
  470.     },
  471.  
  472.     restore: function (aName) {
  473.         let file = persist.getFile(aName);
  474.         let str;
  475.  
  476.         try {
  477.             str = util.readTextFile(file.path);
  478.         } catch (x) {
  479.             return null;
  480.         }
  481.  
  482.         return json.decode(str);
  483.     }
  484. };
  485.  
  486. // }} ======================================================================= //
  487.  
  488. function hookApplicationQuit() {
  489.     const topicId = 'quit-application-granted';
  490.  
  491.     function quitObserver() {
  492.         this.register();
  493.     }
  494.  
  495.     quitObserver.prototype = {
  496.         observe: function(subject, topic, data) {
  497.             if (util.getBoolPref(util.getPrefKey("save_session"), true))
  498.                 persist.preserve("clipboard", clip.ring);
  499.  
  500.             this.unregister();
  501.         },
  502.  
  503.         register: function() {
  504.             let observerService = Cc["@mozilla.org/observer-service;1"]
  505.                 .getService(Ci.nsIObserverService);
  506.             observerService.addObserver(this, topicId, false);
  507.         },
  508.  
  509.         unregister: function() {
  510.             let observerService = Cc["@mozilla.org/observer-service;1"]
  511.                 .getService(Ci.nsIObserverService);
  512.             observerService.removeObserver(this, topicId);
  513.         }
  514.     };
  515.  
  516.     new quitObserver();
  517. }
  518.  
  519. // Initialization {{ ======================================================== //
  520.  
  521. function init() {
  522.     hookApplicationQuit();
  523.     
  524.     if (util.getBoolPref(util.getPrefKey("save_session"), true))
  525.     {
  526.         clip.ring = persist.restore("clipboard") || [];        
  527.     }
  528.  
  529.     clip.sync();
  530. }
  531.  
  532. // }} ======================================================================= //
  533.  
  534. init();